﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TheStar.MODEL;
using MODEL;
using TheStar.Lib;

namespace TheStar.GUI
{
    public partial class PrincipalForm : Form
    {
        #region fields
        private readonly Vizinhanca vizinhanca; 
        #endregion

        #region constructors
        public PrincipalForm()
        {
            this.vizinhanca = new Vizinhanca();
            this.InitializeComponent();
        }
        #endregion

        #region form events
        private void btnAdicionar_Click(object sender, EventArgs e)
        {
            this.AdicionarRelacionamento();
        }
        private void btnCalcular_Click(object sender, EventArgs e)
        {
            PreencherEstimativaForm form = new PreencherEstimativaForm(this.vizinhanca.Cidades);
            form.EstimativaPreenchida += new EventHandler<PreencherEstimativaFormEventArgs>(form_EstimativaPreenchida);
            form.ShowDialog(this);
        }

        private void form_EstimativaPreenchida(object sender, PreencherEstimativaFormEventArgs e)
        {
            TheStarAlgorithm algorithm = new TheStarAlgorithm(new ProblemGraph(PrincipalForm.GetFromComboBox(this.cmbOrigem),
                                                                               PrincipalForm.GetFromComboBox(this.cmbDestino),
                                                                               this.vizinhanca,
                                                                               e.Estimativas));

            ShowPathForm showPath = new ShowPathForm(algorithm.Run());
            showPath.ShowDialog(this);
        }
        #endregion

        #region refresh operations
        private void UpdateForm()
        {
            this.BindCidades();
            this.BindGridView();
        }
        private void BindCidades()
        {
            this.cmbDestino.DataSource = this.vizinhanca.Cidades;
            this.cmbOrigem.DataSource = this.vizinhanca.Cidades;
        }
        private void BindGridView()
        {
            Cidade[] cidades = this.vizinhanca.Cidades.ToArray();
            DataTable table = new DataTable();

            #region definindo colunas
            foreach (Cidade cidade in cidades)
            {
                table.Columns.Add(cidade.Nome, typeof(double));
            }
            #endregion

            #region preenchimento das linhas
            foreach (Cidade cidade in cidades)
            {
                DataRow row = table.NewRow();
                foreach (Transition item in this.vizinhanca.GetTransitions(cidade))
                {
                    row[((Cidade)item.Child).Nome] = item.Cost;
                }
                table.Rows.Add(row);
            }
            #endregion

            this.dgvMapa.DataSource = table;

            #region definindo os textos das linhas
            int cidadeCount = cidades.Length;
            for (int i = 0; i < cidadeCount; i++)
            {
                this.dgvMapa.Rows[i].HeaderCell.Value = cidades[i].Nome;
            }
            #endregion
        } 
        #endregion

        #region operations
        private void AdicionarRelacionamento()
        {
            this.vizinhanca.Add(PrincipalForm.GetFromComboBox(this.cmbOrigem), PrincipalForm.GetFromComboBox(this.cmbDestino), double.Parse(this.mtxtCusto.Text));

            this.UpdateForm();
        }
        private static Cidade GetFromComboBox(ComboBox combox)
        {
            if (combox.SelectedValue == null && !string.IsNullOrEmpty(combox.Text))
            {
                return new Cidade(combox.Text);
            }
            else
            {
                return (Cidade)combox.SelectedValue;
            }
        } 
        #endregion

        #region impl problem
        private class ProblemGraph : IProblemGraphEst
        {
            #region fields
            private readonly Cidade first;
            private readonly Cidade destination;
            private readonly Vizinhanca vizinhanca;
            private readonly IDictionary<Cidade, double> estimativas;
            #endregion

            #region constructors
            public ProblemGraph(Cidade first, Cidade destination, Vizinhanca vizinhanca, IDictionary<Cidade, double> estimativas)
            {
                if (first == null)
                {
                    throw new ArgumentNullException("first");
                }
                if (destination == null)
                {
                    throw new ArgumentNullException("destination");
                }
                if (vizinhanca == null)
                {
                    throw new ArgumentNullException("vizinhanca");
                }
                if (estimativas == null)
                {
                    throw new ArgumentNullException("estimativas");
                }

                this.first = first;
                this.destination = destination;
                this.vizinhanca = vizinhanca;
                this.estimativas = estimativas;
            }
            #endregion

            public double GetEstimatedCost(object from)
            {
                return this.estimativas[(Cidade)from];
            }

            public object First
            {
                get { return this.first; }
            }
            public object Destination
            {
                get { return this.destination; }
            }
            public IEnumerable<Transition> GetChildren(object root)
            {
                return this.vizinhanca.GetTransitions((Cidade)root);
            }
        } 
        #endregion

        private void btnPreencheTudo_Click(object sender, EventArgs e)
        {
            Cidade cidA = new Cidade("A");
            Cidade cidB = new Cidade("B");
            Cidade cidC = new Cidade("C");
            Cidade cidD = new Cidade("D");
            Cidade cidE = new Cidade("E");
            Cidade cidF = new Cidade("F");
            Cidade cidG = new Cidade("G");
            Cidade cidS = new Cidade("S");

            this.vizinhanca.Add(cidA, cidB, 4);
            this.vizinhanca.Add(cidA, cidS, 3);
            this.vizinhanca.Add(cidA, cidD, 5);
            this.vizinhanca.Add(cidB, cidC, 4);
            this.vizinhanca.Add(cidB, cidE, 5);
            this.vizinhanca.Add(cidD, cidS, 4);
            this.vizinhanca.Add(cidD, cidE, 2);
            this.vizinhanca.Add(cidE, cidF, 4);
            this.vizinhanca.Add(cidF, cidG, 3);

            this.UpdateForm();
        }
    }
}
